/**
 * Copyright 2010  Pavel Nemec <nemecp4@gmail.com> <br>
 * <br>
 * License - GPLv3<br>
 *<br>
 * This program is free software; you can redistribute it and/or modify<br>
 * it under the terms of the GNU General Public License as published by<br>
 * the Free Software Foundation; either version 3 of the License, or<br>
 * (at your option) any later version.<br>
 *<br>
 * This program is distributed in the hope that it will be useful,<br>
 * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br>
 * GNU General Public License for more details.<br>
 *<br>
 * You should have received a copy of the GNU General Public License<br>
 * along with this program. If not, see <http://www.gnu.org/licenses/>.<br>
 *<br>
 */
package eu.whowie.jast.client;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.rmi.ConnectException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import eu.whowie.jast.remote.JastClientCallbackHandler;
import eu.whowie.jast.remote.ModuleGroup;
import eu.whowie.jast.remote.UIRemoteInterface;
import eu.whowie.jast.remote.YastModule;
import eu.whowie.jast.remote.YastServer;

/**
 * Main Client class - connect to server using RMI and periodicaly check the
 * connection
 * 
 * @author Pavel Nemec
 * 
 */
public class JastDaemon implements Runnable, JastClientCallbackHandler {

	private Thread thread;
	private Logger logger = Logger.getLogger("JASTDAEMON");
	private YastServer yastServer;

	public JastDaemon() {
		initServer();
		prepareWorker();
	}

	private void initServer() {
		String hostname = "unknown";
		try {
			InetAddress addr = InetAddress.getLocalHost();

			// Get IP Address
			byte[] ipAddr = addr.getAddress();

			// Get hostname
			hostname = addr.getCanonicalHostName();
			if (hostname == null) {
				hostname = addr.getHostAddress();
			}
		} catch (UnknownHostException e) {
		}
		this.yastServer = new YastServer(hostname, hostname);
		HashMap<String, ModuleGroup> groupMap = new HashMap<String, ModuleGroup>();

		File f = new File("/usr/share/applications/YaST2/");
		File[] desktopFiles = f.listFiles(new DesktopFilefilter());
		for (File file : desktopFiles) {
			parseFile(file, groupMap);
		}
		yastServer.setModuleGroup(groupMap.values());

	}

	/**
	 * module is put directly into map
	 * 
	 * @param f
	 * @param groupMap
	 */
	private void parseFile(File f, HashMap<String, ModuleGroup> groupMap) {
		BufferedReader br = null;
		Pattern categoryPattern = Pattern.compile("X-SuSE-YaST-");
		Pattern execPattern = Pattern.compile("/sbin/yast2 ");
		Matcher matcher = null;

		String icon = null, name = null, exec = null, category = null;
		try {
			br = new BufferedReader(new FileReader(f));
			String line;
			while ((line = br.readLine()) != null) {
				if (line.startsWith("Icon=")) {
					icon = line.replaceFirst("Icon=", "");
					continue;
				}
				matcher = execPattern.matcher(line);
				if (matcher.find()) {
					int position = matcher.end();
					exec = line.substring(position, line.length() - 1);
					continue;
				}
				if (line.startsWith("Name=")) {
					name = line.replaceFirst("Name=", "");
					continue;
				}
				matcher = categoryPattern.matcher(line);
				if (matcher.find()) {
					int position = matcher.end();
					category = line.substring(position, line.length() - 1);
				}

			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if (category == null) {
			logger.log(Level.WARNING,
					"got module without category: " + f.getName());
			category = "unknown";
		}
		if (!groupMap.containsKey(category)) {
			groupMap.put(category, new ModuleGroup(category));
		}
		groupMap.get(category).addModule(new YastModule(name, icon, exec));
	}

	private void prepareWorker() {
		this.thread = new Thread(this);
		thread.setName("JastConnectionDaamon");
		// thread.setDaemon(true);
		thread.start();
	}

	@Override
	public void run() {
		boolean connected = false;
		boolean registered = false;
		JastRmiClient client = null;
		UIRemoteInterface ui = null;
		while (true) {

			while (!connected) {
				try {
					client = new JastRmiClient();
					connected = true;
					logger.log(Level.INFO, "connected");
				} catch (RemoteException e) {
					logger.log(Level.FINE, "connection failed");
					try {
						Thread.sleep(500);
					} catch (InterruptedException e1) {
					}
				}
			}
			if (!registered) {
				ui = null;
				try {
					ui = client.getUi();
					ui.connect(yastServer);
					client.export(this, yastServer.getName());

					registered = true;
					logger.log(Level.INFO,
							"succesfully connected to server and export handler");
				} catch (ConnectException e) {
					logger.log(Level.INFO, "not yet connected");
				} catch (RemoteException e) {
					logger.log(Level.WARNING, "cant connect", e);
					connected = false;
				} catch (NotBoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} else {
				// test connection by ping
				long ping = (long) ((1000) * Math.random());
				long pong;
				try {
					pong = ui.ping(ping);
				} catch (RemoteException e) {
					logger.log(Level.FINE, "re when pinging ", e);
					pong = -1;
				}
				if (ping != pong) {
					logger.severe("connection disrupted, fake disconnecting");
					registered = false;
					connected = false;

				}
			}
			// now sleep and wait
			try {
				Thread.sleep(1000);

			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * eu.whowie.jast.remote.JastClientCallbackHandler#startJastModule(eu.whowie
	 * .jast.remote.YastModule)
	 */
	@Override
	public void startJastModule(YastModule module) {
		logger.info("should start module: " + module);

	}

	public static void main(String[] argc) {
		JastDaemon daemon = new JastDaemon();
	}
}
